package year2019.month08;

import java.util.HashMap;
import java.util.Objects;

/**
 * HashMap的简单实现
 * @param <K>
 * @param <V>
 */
public class MyHashMap<K,V> {
    class Node<K, V>{
        private final K key;
        private V value;
        private Node<K, V> next;
        Node(K key, V value){
            this.key=key;
            this.value=value;
        }
        public final K getKey(){
            return key;
        }
        public final V getValue(){
            return value;
        }
        public V setValue(V newValue){
            V oldValue = value;
            value = newValue;
            return oldValue;
        }

        public Node<K, V> getNext() {
            return next;
        }

        public void setNext(Node<K, V> next) {
            this.next = next;
        }

        public final int hashCode() {
            return Objects.hashCode(key) ^ Objects.hashCode(value);
        }
    }

    private Node<K, V>[] elementTable;
    private int size;

    public MyHashMap(){
        elementTable= (Node<K, V>[]) new Node[10];
    }

    public MyHashMap(int size){
        if (size>0){
            elementTable = (Node<K, V>[]) new Node[size];
        } else if (size==0){
            elementTable = (Node<K, V>[]) new Node[0];
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+ size);
        }
    }


    public V put(K key, V value){
        int oldCapacity = elementTable.length;
        if (size>=oldCapacity-1){
            Node<K, V>[] newElementTable = (Node<K, V>[]) new Node[oldCapacity<<1];  //每次增长一倍
            System.arraycopy(elementTable,0,newElementTable,0,oldCapacity);
            elementTable=newElementTable;
        }
        Node<K,V> newNode=new Node<>(key,value);
        Node<K,V> node=null;
        for (int i=0; i<size; i++){
            Node<K,V> element = elementTable[i];
            if (element.getKey().hashCode()==key.hashCode()){
                node = element;
                break;
            }
        }
        V oldValue = null;
        if (node==null){
            elementTable[size++]=newNode;
        } else {
            Node<K,V> lastNode = node;
            boolean isEquals = false;
            do {
                if (lastNode.getKey().equals(key)) {
                    oldValue = lastNode.getValue();
                    lastNode.setValue(value);
                    isEquals = true;
                    break;
                } else {
                    lastNode = lastNode.getNext();
                }
            } while (lastNode.getNext()!=null);

            if (!isEquals){
                oldValue = lastNode.getValue();
                lastNode.setNext(newNode);
            }
        }
        return oldValue;
    }

    public V get(K key){
        Node<K,V> node=null;
        for (int i=0; i<size; i++){
            Node<K,V> element = elementTable[i];
            if (element.getKey().equals(key)){
                node = element;
                break;
            }
        }
        if (node==null){
            return null;
        } else {
            while (node.getNext()!=null){
                node = node.getNext();
            }
            return node.getValue();
        }
    }


    public static void main(String[] args){
        HashMap hashMap = new HashMap();
        hashMap.put("key","valueHashMap");
        System.out.println(hashMap.get("key"));

        MyHashMap myHashMap = new MyHashMap();
        myHashMap.put("key","valueMy");
        myHashMap.put("key","valueMyChange");
        myHashMap.put("key","valueMyNow");
        myHashMap.put("key1","valueMy1");
        myHashMap.put("key2","valueMy2");
        myHashMap.put("key3","valueMy2");
        myHashMap.put("key4","valueMy2");
        myHashMap.put("key5","valueMy2");
        myHashMap.put("key6","valueMy2");
        myHashMap.put("key7","valueMy2");
        myHashMap.put("key8","valueMy2");
        myHashMap.put("key9","valueMy2");
        myHashMap.put("key10","valueMy2");
        myHashMap.put("key11","valueMy2");
        myHashMap.put("key12","valueMy2");
        System.out.println(myHashMap.get("key"));
        System.out.println(myHashMap.get("key1"));
        System.out.println(myHashMap.get("key2"));
    }

}
